/*
 * FNILocale - Localization library for JavaScript 
 * Copyright (C) 2008 - 2009 Antti Leppä / Foyt
 * http://www.foyt.fi
 * 
 * License: 
 * 
 * Licensed under GNU Lesser General Public License Version 2.1 or later (the "LGPL") 
 * http://www.gnu.org/licenses/lgpl.html
 */

fni.locale.FNILocale = Class.create(
  /** @lends fni.locale.FNILocale# */ 
  {
  /**
   * Class constructor
   * @class Class that handles localization
   * @constructs
   */
  initialize : function() {
    this._locales = new Object();
    this._settings = new Object();
    this._loadedLocales = new Hash();
    this._defaultLocale = 'en_US';
  },
  /**
   * Returns timestamp as string formatted by pattern specified in "dateFormatLong" or "dateFormatShort" setting. 
   * 
   * @param {Number} timestamp timestamp
   * @param {Boolean} longFormat if true "dateFormatLong" setting should be used otherwise "dateFormatShort" is used
   * 
   * @returns {String} formatted date string
   */
  getDate: function (timestamp, longFormat) {
    var d = new Date(timestamp);
    return this.getDateFormat(longFormat).format(this, d);
  },  
  /**
   * Returns timestamp as string formatted by pattern specified in "timeFormat" setting. 
   * 
   * @param {Number} timestamp timestamp
   * 
   * @returns {String} formatted time string
   */
  getTime: function (timestamp) {
    var d = new Date(timestamp);
    return this.getTimeFormat().format(this, d);
  },
  /**
   * Returns timestamp as string formatted by pattern specified in "timeFormat" setting. 
   * 
   * @param {Number} timestamp timestamp
   * 
   * @returns {String} formatted time string
   */
  getDateTime: function (timestamp, longFormat) {    
    return this.getDate(timestamp, longFormat) + ' ' + this.getTime(timestamp);
  },
  /**
   * Returns localized text for key in current locale
   * 
   * @param {String} key 
   * @param {String} param1&#44;&#32;param2&#44;&#32;param3&#46;&#46;&#46; locale parameters  
   * 
   * @returns {String} localized string
   */
  getText: function() {
    var params = new Array();
    params.push(this.getLocale());
    var args = $A(arguments);
    for (var i = 0, l = args.length; i < l; i++) {
      params.push(args[i]); 
    }
    
    return this.getLocalizedText.apply(this, params);
  },
  /**
   * Returns localized text for key in specified locale
   * 
   * @param {Locale} locale locale in where text is returned  
   * @param {String} key 
   * @param {String} param1&#44;&#32;param2&#44;&#32;param3&#46;&#46;&#46; locale parameters  
   * 
   * @returns {String} localized string
   */
  getLocalizedText: function () {
    var args = $A(arguments);
    var locale = args[0];
    var text = args[1]; 
    
    var localeVault = this._getLocaleVault(locale);

    if (localeVault) {
      var localizedText = localeVault[text];
      if (localizedText == undefined) {
        localizedText = '[[' + text + ']]';
      } else {
        for (var i = 2; i < args.length; i++) {
          localizedText = localizedText.replace('\{' + (i - 2) + '\}', arguments[i]);
        }
      }
        
      return localizedText;  
    } else {
      return '[[' + text + ']]';
    }
  },
  /**
   * Sets current language (e.g. en in en_US)
   * 
   * @param language {String} language 
   */
  setLanguage: function (language) {
    this._dateFormatShort = undefined;
    this._dateFormatLong = undefined;
    this._timeFormat = undefined;

    this._currentLanguage = language;
  },
  /**
   * Sets current country (e.g. US in en_US)
   * 
   * @param language {String} language 
   */
  setCountry: function (country) {
    this._dateFormatShort = undefined;
    this._dateFormatLong = undefined;
    this._timeFormat = undefined;
    
    this._currentCountry = country;
  },
  /**
   * Returns current country code
   * 
   * @returns {String} current country code
   */
  getCountry: function () {
    return this._currentCountry;
  },
  /**
   * Sets current locale
   * 
   * @param locale {Locale}
   */
  setLocale: function (locale) {
    var splitted = locale.split('_');
    if (splitted.length == 2) {
      this.setLanguage(splitted[0]);
      this.setCountry(splitted[1]);
    } else {
      this.setLanguage(splitted[0]);
      this.setCountry(null);
    }
  },
  /**
   * Returns current language
   * 
   * @returns {String} current language
   */
  getLanguage: function () {
    return this._currentLanguage;
  },
  /**
   * Returns current locale
   * 
   * @returns {Locale} current locale
   */
  getLocale: function () {
    return this.getLanguage() + '_' + this.getCountry();
  },
  /**
   * Returns current date format.  
   * 
   * @param longFormat {Boolean} if true "dateFormatLong" setting should be used otherwise "dateFormatShort" is used 
   * 
   * @returns Current date format
   */
  getDateFormat: function (longFormat) {
    if (longFormat == true) {
      if (!this._dateFormatLong) {
        var dateFormatString = this.getSetting("dateFormatLong");
        if (!dateFormatString||dateFormatString.blank()||(dateFormatString == '[[dateFormatLong]]'))
          dateFormatString = 'dd.MMMM.yyyy';
        
        this._dateFormatLong = new fni.locale.dateformat.FNIDateFormat(dateFormatString);
      }
      
      return this._dateFormatLong;
    } else {
      if (!this._dateFormatShort) {
        var dateFormatString = this.getSetting("dateFormatShort");
        if (!dateFormatString||dateFormatString.blank()||(dateFormatString == '[[dateFormatShort]]'))
          dateFormatString = 'dd.MM.yyyy';
        
        this._dateFormatShort = new fni.locale.dateformat.FNIDateFormat(dateFormatString);
      }
      
      return this._dateFormatShort;
    }
  },
  /**
   * Returns current time format.  
   * 
   * @returns Current time format
   */
  getTimeFormat: function () {
    if (!this._timeFormat) {
      var timeFormatString = this.getSetting("timeFormat");
      if (!timeFormatString||timeFormatString.blank()||(timeFormatString == '[[timeFormat]]'))
        timeFormatString = 'kk:mm';
      
      this._timeFormat = new  fni.locale.dateformat.FNIDateFormat(timeFormatString);
    }
        
    return this._timeFormat;
  },
  /**
   * Returns loaded locales
   * 
   * @returns {Locale[]} loaded locales
   */
  getLocales: function () {
    return this._loadedLocales.keys();
  },
  /**
   * Returns loaded languages
   * 
   * @returns {String[]} loaded languages
   */
  getLanguages: function () {
    var result = new Array();
    var locales = this.getLocales();
    for (var i = 0, l = locales.length; i < l; i++) {
      result.push(locales[i].split('_')[0]);
    }
    
    return result;
  },
  /**
   * Returns setting value for current locale
   * 
   * @param name setting name
   * @returns {String} setting
   */
  getSetting: function (name) {
    var settingsVault = this._getSettingVault(this.getLocale());
    if (settingsVault)
      return settingsVault[name];
    else 
      return "[[" + name + "]]";
  },
  /**
   * Sets setting for current locale
   * 
   * @param name {String} setting name
   * @param value {String} setting value 
   */
  setSetting: function (name, value) {
    var settingsVault = this._getSettingVault(this.getLocale());
    if (settingsVault)
      settingsVault[name] = value;
  },
  /**
   * Loads locales from JSON.
   * 
   * JSON format should be: 
   * 
   * <pre>{ 
   *   localeStrings: {
   *     key: value
   *   },
   *   settings: {
   *     key: value
   *   }
   * }</pre> 
   * 
   * @param locale locale to be loaded
   * @param file url to JSON file
   */
  loadLocale: function (locale, file) {
    var _this = this;
    new Ajax.Request(file, {
      onSuccess: function (transport) {
        try {
          var json = transport.responseText.evalJSON();
          
          for (var key in json.localeStrings) {
            _this._setLocaleString(locale, key, json.localeStrings[key]);
          }
          
          for (var key in json.settings) {
            _this._setLocaleSetting(locale, key, json.settings[key]);
          }
          
          _this._loadedLocales.set(locale, true);
        } catch (e) {
          alert("Locale " + file + " loading failed:" + e);
        }
      },
      asynchronous: false
    });
  },
  /**
   * @private
   */ 
  _getLocaleVault: function (locale) {
    var localeVault = this._locales[locale];
    if (!localeVault) {
      var s = locale.split("_");
      if (s.length == 2)
        localeVault = this._locales[s[0]];
    }
    
    if (!localeVault)
      localeVault = this._locales[this._defaultLocale];
    
    return localeVault;
  },
  /**
   * @private
   */
  _getSettingVault: function (locale) {
    var settingsVault = this._settings[locale];
    if (!settingsVault) {
      var s = locale.split("_");
      if (s.length == 2)
        settingsVault = this._settings[s[0]];
    }
    
    if (!settingsVault)
      settingsVault = this._settings[this._defaultLocale];
    
    return settingsVault;
  },
  /**
   * @private
   */
  _setLocaleString: function (locale, key, string) {
    if (!this._locales[locale])
      this._locales[locale] = new Object();
    
    var s = locale.split('_');
    
    if (s.length == 2) {
      var lang = s[0];
      if (!this._locales[lang])
        this._locales[lang] = new Object();
      
      this._locales[locale][key] = string;
      this._locales[lang][key] = string;      
    } else {
      this._locales[locale][key] = string;
    }
  },
  /**
   * @private
   */
  _setLocaleSetting: function (locale, key, setting) {
    if (!this._settings[locale])
      this._settings[locale] = new Object();
    
    var s = locale.split('_');
    if (s.lenght == 2) {
      if (!this._settings[lang])
        this._settings[lang] = new Object();
      
      this._settings[locale][key] = setting;
      this._settings[lang][key] = setting;
    } else {
      this._settings[locale][key] = setting;
    }
  }
});

/**
 * TODO
 */
Object.extend(fni.locale.FNILocale.prototype, fni.events.FNIEventSupport);